package com.jj.net.tcp;

import com.jj.config.Constants;
import com.jj.core.rpc.RPCManager;
import com.jj.core.rpc.UserCallManager;
import com.jj.message.ProtoFormat;
import com.jj.message.Result;
import com.jj.message.battle.UserMessage;
import com.jj.net.ChannelListener;
import com.jj.net.Context;
import com.jj.net.Message;

import com.jj.service.player.Player;
import com.jj.service.player.PlayerManager;
import com.jj.service.room.Room;
import com.jj.service.room.RoomManager;
import com.jj.service.user.GenericRPCProxy;
import com.jj.service.user.UserService;
import org.apache.commons.collections4.map.LRUMap;
import org.beykery.jkcp.KcpServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

/**
 * Copyrights: QidianGroup@JJ
 *
 * @author: LuHan
 * @date: 2018/1/15, 13:12
 */
@Component
public class TcpChannelListener extends RPCManager implements ChannelListener{
    private static Logger logger = LoggerFactory.getLogger(TcpChannelListener.class);

    @Autowired
    private UserCallManager userCallManager;

    @Autowired
    private UserService userService;

    @Autowired
    private GenericRPCProxy genericRPCProxy;

    @Autowired
    private PlayerManager playerManager;

    @Autowired
    private RoomManager roomManager;

    @PostConstruct
    public void init(){
        regRPCHandler(userService);
        regRPCHandler(genericRPCProxy);
    }

    private LRUMap<Long, Context> contextMap = new LRUMap<>(20*1024);


    public void bind(Long uid, Context context){
        synchronized (contextMap){
            contextMap.put(uid, context);
        }
    }

    public void unbind(Long uid){
        synchronized (contextMap){
            contextMap.remove(uid);
        }
    }

    public Context findContextByUid(Long uid){
        playerManager.leave(uid);
        roomManager.leave(uid);

        synchronized (contextMap) {
            return contextMap.get(uid);
        }

    }

    @Override
    public void onRcv(Message message, Context ctx) {
        logger.debug("rcv msg {} from {}", message, ctx.getChannel().remote());
        UserMessage userMessage = (UserMessage)message;
        int id = userMessage.getMsgID();
        Object response = null;
        try{
            Long uid = (Long) ctx.getAttr(Constants.USER_ID_KEY);
            if(uid != null){
                logger.debug("rcv {} from {}", message, uid);
            }
        }catch (Throwable t){
            logger.error("exception", t);
        }

        try {
            if (userMessage.getProtocolFormat() == ProtoFormat.Standard) {
                //自定义格式
                Object[] params =
                        userCallManager.getParameters(
                                (int) userMessage.getMsgID(), userMessage.getPayload());
                response = call(id, params, ctx);
            } else {
                //其他都是JSON格式
                String jsonArgsStr = userMessage.getJsonMsg();
                response = call(id, jsonArgsStr, ctx);
            }
        }
        catch (Throwable t){
            logger.error("exception", t);
            Result<String> exp = new Result<>();
            exp.setCode(1);
            exp.setValue(t.getMessage());
            response = clientManager.msg().onReturn(exp);
        }

        if(response != null && response instanceof UserMessage){
            UserMessage respUserMsg = (UserMessage)response;
            //response_id = request_id + 1
            // msgid=0，是GM指令，序号不能加1
            if(userMessage.getMsgID() != 0)
            {
                respUserMsg.setMsgID((short) (userMessage.getMsgID()+1));
            }
            //set request id if exist
            if(userMessage.getRequestId() != null){
                respUserMsg.setRequestId(userMessage.getRequestId());
            }
            if(userMessage.getProtocolFormat() == ProtoFormat.Request){
                respUserMsg.setProtocolFormat(ProtoFormat.Response);
            }
            ctx.send((Message) response);
        }
    }

    @Override
    public void send(Message message, Context ctx) {

    }

    @Override
    public void onClosed(Context ctx) {
        Long uid = (Long) ctx.getAttr(Constants.USER_ID_KEY);
        logger.debug("onClose from {}, uid:{}", ctx.getChannel().remote(), uid);
        if(uid != null){
            Player player = playerManager.getPlayer(uid);
            unbind(uid);
            if(player != null){
                Room room = player.getRoom();
                if(room != null){
                    room.leave(uid);
                }else{
                    logger.debug("room not found for {}", uid);
                }
            }else{
                logger.debug("player {} not found", uid);
            }
        }else{
            logger.warn("unbinded session, ignore closed from {}.",
                    ctx.getChannel().remote());
        }
    }

    @Override
    public void onOpen(Context ctx) {

    }


}
